package pl.pw.mkmw.pnganimator.image;

import java.awt.Color;
import java.util.Arrays;

/**
 *
 * @author MK
 */
public class SImage {

    private byte[][] red;
    private byte[][] green;
    private byte[][] blue;
    private byte[][] alpha;

    /*
     * anyChannel[Y][X]
     *   X X X
     * Y
     * Y
     * Y
     */
    public SImage(Color[][] table) {
        initTables(table[0].length, table.length);
        for (int y = 0; y < table.length; y++) {
            for (int x = 0; x < table[0].length; x++) {
                this.red[y][x] = (byte) table[y][x].getRed();
                this.green[y][x] = (byte) table[y][x].getGreen();
                this.blue[y][x] = (byte) table[y][x].getBlue();
                this.alpha[y][x] = (byte) table[y][x].getAlpha();
            }
        }
    }

    public SImage(int[][] red, int[][] green, int[][] blue) throws Exception {
        this.red = getByteArrayFrom(red);
        this.green = getByteArrayFrom(green);
        this.blue = getByteArrayFrom(blue);
        fullyOpaqueAlpha(red[0].length, red.length);
    }

    private byte[][] getByteArrayFrom(int[][] intArray) {
        byte[][] toReturn = new byte[intArray.length][intArray[0].length];
        for (int y = 0; y < intArray.length; y++) {
            for (int x = 0; x < intArray[0].length; x++) {
                toReturn[y][x] = (byte) intArray[y][x];
            }
        }
        return toReturn;
    }

    private int[][] getIntArrayFrom(byte[][] byteArray) {
        int[][] toReturn = new int[byteArray.length][byteArray[0].length];
        for (int y = 0; y < byteArray.length; y++) {
            for (int x = 0; x < byteArray[0].length; x++) {
                toReturn[y][x] = (int) byteArray[y][x] & 0xff;
            }
        }
        return toReturn;
    }

    public SImage(int[][] red, int[][] green, int[][] blue, int[][] alpha) {
        this.red = getByteArrayFrom(red);
        this.green = getByteArrayFrom(green);
        this.blue = getByteArrayFrom(blue);
        this.alpha = getByteArrayFrom(alpha);
    }

    private void initTables(int width, int height) {
        this.red = new byte[height][width];
        this.green = new byte[height][width];
        this.blue = new byte[height][width];
        this.alpha = new byte[height][width];

    }

    private void fullyOpaqueAlpha(int width, int height) throws Exception {
        throw new Exception("Dont use that!");
//        this.alpha = new byte[height][width];
//        for (int x = 0; x < width; x++) {
//            for (int y = 0; y < height; y++) {
//                this.alpha[y][x] = (byte) 255;
//            }
//        }
    }

    public int[][] getRed() {
        return getIntArrayFrom(red);
    }

    public void setRed(int[][] red) {
        this.red = getByteArrayFrom(red);
    }

    public int[][] getGreen() {
        return getIntArrayFrom(green);
    }

    public void setGreen(int[][] green) {
        this.green = getByteArrayFrom(green);
    }

    public int[][] getBlue() {
        return getIntArrayFrom(blue);
    }

    public void setBlue(int[][] blue) {
        this.blue = getByteArrayFrom(blue);
    }

    public int[][] getAlpha() {
        return getIntArrayFrom(alpha);
    }

    public void setAlpha(int[][] alpha) {
        this.alpha = getByteArrayFrom(alpha);
    }

    public int getWidth() {
        if (red == null) {
            return 0;
        }
        if (red[0] == null) {
            return 0;
        }
        return red[0].length;
    }

    public int getHeight() {
        if (red == null) {
            return 0;
        }
        return red.length;
    }

    public int getRed(int x, int y) {
        return red[y][x] & 0xff;
    }

    public int getGreen(int x, int y) {
        return green[y][x] & 0xff;
    }

    public int getBlue(int x, int y) {
        return blue[y][x] & 0xff;
    }

    public int getAlpha(int x, int y) {
        return alpha[y][x] & 0xff;
    }

    public Color[][] getColor() {
        Color[][] toReturn = new Color[red.length][red[0].length];
        for (int y = 0; y < red.length; y++) {
            for (int x = 0; x < red[0].length; x++) {
                toReturn[y][x] = new Color(red[y][x] & 0xff, green[y][x] & 0xff, blue[y][x] & 0xff, alpha[y][x] & 0xff);
            }
        }
        return toReturn;
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder("RED:\n");

        for (int y = 0; y < red.length; y++) {
            for (int x = 0; x < red[0].length; x++) {
                sb.append(red[y][x] & 0xff).append(" ");
            }
            sb.append("\n");
        }
        sb.append("GREEN:\n");
        for (int y = 0; y < green.length; y++) {
            for (int x = 0; x < green[0].length; x++) {
                sb.append(green[y][x] & 0xff).append(" ");
            }
            sb.append("\n");
        }
        sb.append("BLUE:\n");
        for (int y = 0; y < blue.length; y++) {
            for (int x = 0; x < blue[0].length; x++) {
                sb.append(blue[y][x] & 0xff).append(" ");
            }
            sb.append("\n");
        }
        sb.append("ALPHA:\n");
        for (int y = 0; y < alpha.length; y++) {
            for (int x = 0; x < alpha[0].length; x++) {
                sb.append(alpha[y][x] & 0xff).append(" ");
            }
            sb.append("\n");
        }

        return sb.toString();
    }

    @Override
    public int hashCode() {
        int hash = 3;
        hash = 53 * hash + Arrays.deepHashCode(this.red);
        hash = 53 * hash + Arrays.deepHashCode(this.green);
        hash = 53 * hash + Arrays.deepHashCode(this.blue);
        hash = 53 * hash + Arrays.deepHashCode(this.alpha);
        return hash;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final SImage other = (SImage) obj;
        if (!Arrays.deepEquals(this.red, other.red)) {
            return false;
        }
        if (!Arrays.deepEquals(this.green, other.green)) {
            return false;
        }
        if (!Arrays.deepEquals(this.blue, other.blue)) {
            return false;
        }
        if (!Arrays.deepEquals(this.alpha, other.alpha)) {
            return false;
        }
        return true;
    }

    public byte[] getWholePixelAt(int x, int y) {
        return new byte[]{(byte) red[y][x], (byte) green[y][x], (byte) blue[y][x], (byte) alpha[y][x]};
    }
}
